home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / objcissu.lha / forward-performv < prev    next >
Internet Message Format  |  1993-02-27  |  46KB

  1. Date: Mon, 18 Jan 93 15:34:32 -0600
  2. From: burchard@geom.umn.edu
  3. To: gnu-objc@prep.ai.mit.edu
  4. Subject: The forward/performv Puzzle
  5.  
  6. I have written a very, very, very preliminary socket-based distributed object system that is intended for porting to GNU Objective-C.  So far, this has been primarily an exercise to see what is actually required from the run-time in order to implement such a system.
  7.  
  8. There is one major feature missing from GNU's Objective-C run-time at the moment, which prevents this project from progressing to the more desirable very, very preliminary :-) stage.  That feature is the functionality of NeXT's forward and performv, which are required in order that arbitrary messages can be captured by proxy objects and then later executed by the remote objects they stand for.
  9.  
  10. The puzzle I would like to pose to this mailing list is how such a run-time facility can best (most portably) be implemented.  It doesn't have to be compatible with NeXT's forward and performv; it just needs to provide their capabilities (in fact, NeXT's API is proabably a good one to avoid).
  11.  
  12. This is a tricky puzzle, though, the underlying difficulty being that the C language does not support the run-time construction of argument lists and return values.  (It doesn't really support the run-time deconstruction of argument lists either, except that we now have standard hack for it called "stdarg.h".)
  13.  
  14. This puzzle is ironically made more difficult by the portable message-dispatching implementation chosen by GNU Obj-C.  The problem here is that objc_msgSend() only gets to choose a method implementation, and is helpless to change the message's "self" and "_cmd" (which are hard-compiled into the message call in the GNU run-time system).  If this were not the case, a limited form of forwarding could be implemented portably.
  15.  
  16. This portability puzzle vexes NeXT's distributed object system as well, resulting in problems like not being able to return doubles from remote messages.
  17.  
  18. The benefits of distributed objects are too great, though, to abandon this quest if it turns out that no 100% pure solution exists.  More portable is better, but I'd like to hear any practical ideas that will work well with the GNU compiler.
  19.  
  20. Solutions?  Ideas, anyone?
  21.  
  22. Thanks,
  23. --------------------------------------------------------------------
  24. Paul Burchard    <burchard@geom.umn.edu>
  25. ``I'm still learning how to count backwards from infinity...''
  26. --------------------------------------------------------------------
  27.  
  28.  
  29.  
  30. Date: Tue, 19 Jan 93 08:05:01 -0800
  31. From: Dennis Glatting <dglattin@trirex.com>
  32. To: <burchard@geom.umn.edu>
  33. Subject: Re: The forward/performv Puzzle
  34. Cc: gnu-objc@prep.ai.mit.edu
  35. Reply-To: dennis_glatting@trirex.com
  36.  
  37.  
  38. I looked at doing forwardv:: for the first release of the run time.  To implement forwardv:: is a perplexing problem:  
  39.  
  40. * Implementation of forwardv:: would require stack frame copying.  (or at least modification of the existing stack frame.)
  41. * The microprocessor itself poses problems such as word width, alignment, and -- possibly on some RISC machines -- parameter passing using register windows.
  42. * Each function used to implement forwardv:: may need to know the amount of data pushed onto the stack for local variables.  (So to index backward.)
  43. * The dispatch function must know about passed arguments.  While this is encoded and available, what do you do for variable arguments and structures?  Oh yea, how about void*?
  44. * The stack must be indexed to extract return addresses -- that is, if this can be done with your microprocessor of the day.  There are also microprocessor/compiler specific data pushed onto the stack that the functions may need to know about such as the variable frame on 680x0 microprocessors (note the link instruction on each function entry).
  45.  
  46. At the time, these issues and others I haven't mentioned caused me think that DO reeks of assembly code that is not only tailored to the microprocessor, by the vendor's operating system as well.  This is a significant maintenance issue and is in no way portable.
  47.  
  48. The other item I wanted to add to the run time is "active objects" but it suffers from many of the same issues.
  49.  
  50. I think you touched on something I suspect about the NeXT run time:  it contains microprocessor/vendor specific assembly code.
  51.  
  52. I invite ideas of how to do this in a somewhat portable fashion.  Portability was one of the chief goals of the run time.
  53.  
  54.  
  55. -dpg
  56.  
  57.  
  58.  
  59.  
  60. From: Steve Naroff <Steve_Naroff@next.com>
  61. Date: Tue, 19 Jan 93 17:50:24 -0800
  62. To: dennis_glatting@trirex.com
  63. Subject: The forward/performv Puzzle
  64. Cc: gnu-objc@prep.ai.mit.edu
  65.  
  66.  
  67. The "style" of forwarding required for DO is hard to do in portable way (given the low level nature of C). C compilers have a hard enough time agreeing on structure layout! Nevertheless, I believe you are over estimating the assembly required implement this. The two hooks in the NeXT runtime that support forwarding are:
  68.  
  69. extern id _objc_msgForward (id self, SEL sel, ...);
  70. extern id objc_msgSendv (id self, SEL op,
  71.         unsigned arg_size, marg_list arg_frame);
  72.  
  73. The assembly code amounts to less than 1 page for both of these routines (let me know if you want the code).
  74.  
  75. You could imagine a style of forwarding that works fine locally (and is totally portable). The interface is:
  76.  
  77. - forward:(SEL)op;    // adequate for supporting delegation.
  78.  
  79. "forward:" would be implemented by any class interested in providing a delegate. It would not be directly responsible for sending the message (which is why it is more portable). This is also parallel with the way you separate "lookup from dispatch" in the GNU runtime.
  80.  
  81. regards, snaroff.
  82.  
  83. Begin forwarded message:
  84.  
  85. Date: Tue, 19 Jan 93 08:05:01 -0800
  86. From: Dennis Glatting <dglattin@trirex.com>
  87. To: <burchard@geom.umn.edu>
  88. Subject: Re: The forward/performv Puzzle
  89. Cc: gnu-objc@prep.ai.mit.edu
  90. Reply-To: dennis_glatting@trirex.com
  91.  
  92.  
  93. I looked at doing forwardv:: for the first release of the run time.  To implement forwardv:: is a perplexing problem: 
  94.  
  95. * Implementation of forwardv:: would require stack frame copying.  (or at least modification of the existing stack frame.)
  96. * The microprocessor itself poses problems such as word width, alignment, and -- possibly on some RISC machines -- parameter passing using register windows.
  97. * Each function used to implement forwardv:: may need to know the amount of data pushed onto the stack for local variables.  (So to index backward.)
  98. * The dispatch function must know about passed arguments.  While this is encoded and available, what do you do for variable arguments and structures?  Oh yea, how about void*?
  99. * The stack must be indexed to extract return addresses -- that is, if this can be done with your microprocessor of the day.  There are also microprocessor/compiler specific data pushed onto the stack that the functions may need to know about such as the variable frame on 680x0 microprocessors (note the link instruction on each function entry).
  100.  
  101. At the time, these issues and others I haven't mentioned caused me think that DO reeks of assembly code that is not only tailored to the microprocessor, by the vendor's operating system as well.  This is a significant maintenance issue and is in no way portable.
  102.  
  103. The other item I wanted to add to the run time is "active objects" but it suffers from many of the same issues.
  104.  
  105. I think you touched on something I suspect about the NeXT run time:  it contains microprocessor/vendor specific assembly code.
  106.  
  107. I invite ideas of how to do this in a somewhat portable fashion.  Portability was one of the chief goals of the run time.
  108.  
  109.  
  110. -dpg
  111.  
  112.  
  113.  
  114.  
  115.  
  116. Date: Wed, 20 Jan 93 23:40 PST
  117. From: michael@stb.info.com (Michael Gersten)
  118. To: gnu-objc@prep.ai.mit.edu
  119. Subject: Re: The forward/performv Puzzle
  120.  
  121. Here's my comments on how to forward:
  122.  
  123. The issue is how to portable forward a call to someone else, given that you don't know how far up the stack the stack frame runs, nor the format of said stack frame.
  124.  
  125. Method one:
  126. You decide to pass a message to an object. You call the dispatcher. The dispatcher must do one of two things: It must either call (or return the address of) the specified routine, or failing that, the "forward" routine.
  127.  
  128. Assumptions used: The number of arguments declared to be taken by the routine (in this case, an arbitrary number of args from the original routine, and the probably 0 args declared by the forward routine) do not affect the format of the stack frame.
  129.  
  130. Disadvantages: Cannot retreive the arguments in the forward routine, nor can the forward routine pass those arguments to another routine.
  131.  
  132. Method two:
  133. All method calls get another arg pushed on the stack, an invisible arg specifying how many bytes have been pushed on the stack. This is used to determine the stack size, which can then be "independently" copied
  134. Advantages: Fairly portable (see below)
  135. Disadvantages: Does not properly handle the case of one arg being a pointer to another arg -- you'll have instead a pointer to something back up the stack in another frame.
  136.     Still relies on the forward method knowing the stack info.
  137.  
  138. Method three:
  139. Attempting to emulate the next mechanism:
  140. The forward method will be called with a special argument type, that can only be used by passing it to the performv method. The performv method will use this special type, with the goal of being implementation independent, to call the routine.
  141.  
  142. In order for performv to be so independent, it must take the new object, the new method name, and the old info; it would then unwind the stack to the point indicated in the special argument, modifies the stack frame in place to substitute the new object (which may be the same as the old), and the new method, and then reruns the send routine.
  143.  
  144. This requires that the send routine, when it fails, must instead send to the forward routine, and with a slightly different stack frame -- it needs to put onto the stack a new stack frame specifying the original object, the original method, and this special argument for performv.
  145.  
  146. Advantages: It works. It's fairly portable. It doesn't break under any arg types
  147. Disadvantages: Requires that the machine have some way to unwind a stack frame (does this conflict with register windows machines?). This code (the unwinding of the stack, and the setting up info needed to unwind) would probably be machine specific, and only used in one or two places (not really much different than requiring each machien description to provide a prologue and epilogue routine). Not completely compatible with a message dispatcher that works by returning a pointer for someone else to call -- would require that the code so involved change from
  148.  
  149.     push args
  150.     push obj
  151.     push method
  152.     call lookup
  153.     jump addr
  154.  
  155. to
  156. ...
  157.     call lookup
  158.     jump NZ,addr
  159.     jump massage_stack_and_forward
  160.  
  161. other arg passing conventions may require other changes -- you need a new #define for "the name of the insn pattern to use (usually jne) after calling the method lookup routine; must not jump if a lookup failure occurs". Also not quite standard in the implementation of forward and performv -- note that performv under this system does not return to the caller (forward), but instead to the caller of forward. Since sending a message "method1" to "foo" is translated into a "forward" message, this has the result of returning directly after the call to method1, with no way for that routine to know that a failure occured (and no way for the forward routine to do something AFTER the performv, which may vary well be desireable). No easy way to check for a "double forward", where the forward routine cannot operate because of a failed send (infinite loop in the error handler). Still, it looks like the best of the implementation independent ways. Would someone like to shoot it down please?
  162. --
  163.     Michael Gersten        michael@stb.info.com
  164. NeXT Registered Developer (NeRD) # 3860 -- Hire me! Quick!
  165. Will program computers for food (and net connection, health benefits, cash,...)
  166.  
  167. Date: Thu, 21 Jan 93 11:53:49 -0600
  168. From: burchard@geom.umn.edu
  169. To: michael@stb.info.com (Michael Gersten)
  170. Subject: Re: The forward/performv Puzzle
  171. Cc: gnu-objc@prep.ai.mit.edu
  172.  
  173. > (does this conflict with register windows machines?)
  174.  
  175. To avoid lots of hypothetical discussions, I suggest everyone thinking about this take a look at section 14.7 of the GNU CC manual, on C calling conventions (about a dozen pages).  It was an eye-opener for me---I hadn't realized that some platforms will go so far as to split a single argument into pieces, and pass part on the stack and part in a register.  And don't count on there being stack space "reserved" for the missing args/pieces that are passed in registers.
  176.  
  177. The varargs facilities in GNU CC provide a bit of guidance but not a lot of actual help.  The one thing that could be helpful is the builtin "function" __builtin_saveregs().  Don't try taking a pointer to this thing---it's really a slippery compiler trick to cause the insertion of some assembly code at the beginning of the routine (no matter where it's "called").  The assembly code for __builtin_saveregs() is maintained for each platform that needs it in libgcc2.c.  Thankfully it isn't, in the end, all that terrible, and gives some hints about how the opposite operation (of loading arguments properly from a more uniform format) would proceed.
  178.  
  179. Still, after looking at all this, I have to regard the stack-oriented argument info maintained and published by the Obj-C runtime as being somewhat euphemistic.
  180.  
  181. --------------------------------------------------------------------
  182. Paul Burchard    <burchard@geom.umn.edu>
  183. ``I'm still learning how to count backwards from infinity...''
  184. --------------------------------------------------------------------
  185.  
  186. Date: Sat, 23 Jan 93 15:04:24 -0500
  187. From: rms@gnu.ai.mit.edu (Richard Stallman)
  188. To: Steve_Naroff@next.com
  189. Cc: dennis_glatting@trirex.com, gnu-objc@prep.ai.mit.edu
  190. In-Reply-To: <9301200150.AA24759@oz.NeXT.COM> (message from Steve Naroff on Tue, 19 Jan 93 17:50:24 -0800)
  191. Subject: The forward/performv Puzzle
  192.  
  193. I woul like to see a feature in C to allow construction of an argument
  194. list with types and number of args chosen at run time,
  195. plus a feature to call a function with such an argument list.
  196. Forwarding could use this feature and would then not need
  197. any assembler language support.
  198.  
  199.  
  200. We would need to have descriptors for types.  They would not
  201. necessarily have to give complete information about the type, but they
  202. would have to give enough to decide how to pass an argument.  Perhaps
  203. a __builtin_classify_type value plus the size would be enough info.
  204.  
  205. Then the arglist would be an array of this structure:
  206.  
  207. struct datum { int typeclass; int size; void *address; };
  208.  
  209. You would call a function using apply:
  210.  
  211. void apply (struct datum value, struct datum *arguments);
  212.  
  213.  
  214. With some work, it would be possible to arrange to write apply
  215. in libgc2.c and make it portable by using the same FUNCTION_ARG...
  216. macros used in expand_call.  We would have to make those macros
  217. use a struct datum rather than a tree node, to represent type info,
  218. and change the machine descriptions, but that is ok.
  219.  
  220.  
  221. Please tell me if you volunteer to write this.
  222.  
  223. Date: Sat, 23 Jan 93 16:29:14 -0600
  224. From: burchard@geom.umn.edu
  225. To: rms@gnu.ai.mit.edu (Richard Stallman)
  226. Subject: Re: The forward/performv Puzzle
  227. Cc: gnu-objc@prep.ai.mit.edu
  228.  
  229. Oops....a couple of typos made their way into our letters...just to avoid any confusion here they are....
  230.  
  231. Richard Stallman wrote:
  232. >  void apply (struct datum value, struct datum *arguments);
  233.  
  234. where I imagine he meant something like:
  235.  
  236.   void apply(struct datum val, void (*func)(), struct datum *args);
  237.  
  238. Then I wrote:
  239. >  static double double_identity_function(x) { return(x); }
  240.  
  241. meaning, of course,
  242.  
  243.   static double double_identity_function(double x) { return(x); }
  244.  
  245. -PB
  246.  
  247. Date: Sat, 23 Jan 93 17:01:04 -0600
  248. From: burchard@geom.umn.edu
  249. To: gnu-objc@prep.ai.mit.edu
  250. Subject: Re: The forward/performv Puzzle [corrected]
  251.  
  252. [ Corrected version of my earlier letter. ]
  253.  
  254. Richard Stallman proposes:
  255. >  void apply (struct datum value, struct datum *arguments);
  256.  
  257. I'm assuming that he meant:
  258.  
  259.   void apply(struct datum val, void (*func)(), struct datum *args);
  260.  
  261. The above is what is needed for performv.  For forwarding (and to get
  262. the full benefit of the above facility) the opposite capability is
  263. also required---namely, the ability for a single function to receive
  264. calls issued with varying prototypes.  This will require two
  265. "functions"
  266.  
  267.   void get_args(struct datum *arguments);
  268.  
  269.   void put_return(struct datum value);
  270.  
  271. In both cases, you'd supply type information; in put_return() you'd also supply the value.
  272.  
  273. In general, these two cannot be honest function calls, since for
  274. example get_args() contains an implicit __builtin_saveregs().
  275. Sometimes kludges are available to avoid assembler insertion, though.
  276. For example, the following hack tricks many platforms into returning a
  277. double from a nominal 32-bit function:
  278.  
  279.   #define RETURN_DOUBLE(x)                \
  280.     ({                        \
  281.     double rtn = x;                    \
  282.     unsigned int fake = *(unsigned int *)&rtn;    \
  283.     double_identity_function(rtn);            \
  284.     return(fake);                    \
  285.     })
  286.  
  287.   /* don't inline this */
  288.   static double double_identity_function(double x) { return(x); }
  289.  
  290.  
  291. Richard further proposes:
  292. >  struct datum { int typeclass; int size; void *address; };
  293.  
  294. I don't think this machine-specific encoding is currently accessible
  295. at run-time, because __builtin_classify_type() is of necessity a
  296. compiler directive rather than an honest function call (due to the way
  297. it is "called").
  298.  
  299. I think what is needed here is a simple, portable type
  300. encoding---which conveniently enough already exists.  The Objective-C
  301. runtime uses a simple string encoding which covers all possible C
  302. types, including compound types.  So I'd suggest
  303.  
  304.   struct datum { const char *typedesc; void *address; };
  305.  
  306. You'd need to write a library function to convert this to the
  307. machine-specific form, but the code for it would be simple, and
  308. more-or-less xeroxed from BUILT_IN_CLASSIFY_TYPE.  Actually, for
  309. better efficiency, we could even leave space in the datum structure
  310. for caching the machine-specific info:
  311.  
  312.   struct datum
  313.   {
  314.       /* User-level information */
  315.       const char *typedesc;
  316.     void *address;
  317.  
  318.     /* System-cached information */
  319.     int typeclass;
  320.     int size;
  321.   };
  322.  
  323. --------------------------------------------------------------------
  324. Paul Burchard    <burchard@geom.umn.edu>
  325. ``I'm still learning how to count backwards from infinity...''
  326. --------------------------------------------------------------------
  327.  
  328.  
  329. Date: Sat, 23 Jan 93 15:20:20 -0600
  330. From: burchard@geom.umn.edu
  331. To: rms@gnu.ai.mit.edu (Richard Stallman)
  332. Subject: Re: The forward/performv Puzzle
  333. Cc: gnu-objc@prep.ai.mit.edu
  334.  
  335. Richard Stallman proposes:
  336. >  void apply (struct datum value, struct datum *arguments);
  337.  
  338. The above is what is needed for performv.  For forwarding (and to get
  339. the full benefit of the above facility) the opposite capability is
  340. also required---namely, the ability for a single function to receive
  341. calls issued with varying prototypes.  This will require two
  342. "functions"
  343.  
  344.   void get_args(struct datum *arguments);
  345.  
  346.   void put_return(struct datum value);
  347.  
  348. In both cases, you'd supply type information; in put_return() you'd
  349. also supply the value.
  350.  
  351. In general, these two cannot be honest function calls, since for
  352. example get_args() contains an implicit __builtin_saveregs().
  353. Sometimes kludges are available to avoid assembler insertion, though.
  354. For example, the following hack tricks many platforms into returning a
  355. double from a nominal 32-bit function:
  356.  
  357.   #define RETURN_DOUBLE(x)                \
  358.     ({                        \
  359.     double rtn = x;                    \
  360.     unsigned int fake = *(unsigned int *)&rtn;    \
  361.     double_identity_function(rtn);            \
  362.     return(fake);                    \
  363.     })
  364.  
  365.   /* don't inline this */
  366.   static double double_identity_function(x) { return(x); }
  367.  
  368.  
  369. Richard further proposes:
  370. >  struct datum { int typeclass; int size; void *address; };
  371.  
  372. I don't think this machine-specific encoding is currently accessible
  373. at run-time, because __builtin_classify_type() is of necessity a
  374. compiler directive rather than an honest function call (due to the way
  375. it is "called").
  376.  
  377. I think what is needed here is a simple, portable type
  378. encoding---which conveniently enough already exists.  The Objective-C
  379. runtime uses a simple string encoding which covers all possible C
  380. types, including compound types.  So I'd suggest
  381.  
  382.   struct datum { const char *typedesc; void *address; };
  383.  
  384. You'd need to write a library function to convert this to the
  385. machine-specific form, but the code for it would be simple, and
  386. more-or-less xeroxed from BUILT_IN_CLASSIFY_TYPE.  Actually, for
  387. better efficiency, we could even leave space in the datum structure
  388. for caching the machine-specific info:
  389.  
  390.   struct datum
  391.   {
  392.       /* User-level information */
  393.       const char *typedesc;
  394.     void *address;
  395.  
  396.     /* System-cached information */
  397.     int typeclass;
  398.     int size;
  399.   };
  400.  
  401. --------------------------------------------------------------------
  402. Paul Burchard    <burchard@geom.umn.edu>
  403. ``I'm still learning how to count backwards from infinity...''
  404. --------------------------------------------------------------------
  405.  
  406. Date: Sat, 23 Jan 93 15:20:20 -0600
  407. From: burchard@geom.umn.edu
  408. To: rms@gnu.ai.mit.edu (Richard Stallman)
  409. Subject: Re: The forward/performv Puzzle
  410. Cc: gnu-objc@prep.ai.mit.edu
  411.  
  412. Richard Stallman proposes:
  413. >  void apply (struct datum value, struct datum *arguments);
  414.  
  415. The above is what is needed for performv.  For forwarding (and to get
  416. the full benefit of the above facility) the opposite capability is
  417. also required---namely, the ability for a single function to receive
  418. calls issued with varying prototypes.  This will require two
  419. "functions"
  420.  
  421.   void get_args(struct datum *arguments);
  422.  
  423.   void put_return(struct datum value);
  424.  
  425. In both cases, you'd supply type information; in put_return() you'd
  426. also supply the value.
  427.  
  428. In general, these two cannot be honest function calls, since for
  429. example get_args() contains an implicit __builtin_saveregs().
  430. Sometimes kludges are available to avoid assembler insertion, though.
  431. For example, the following hack tricks many platforms into returning a
  432. double from a nominal 32-bit function:
  433.  
  434.   #define RETURN_DOUBLE(x)                \
  435.     ({                        \
  436.     double rtn = x;                    \
  437.     unsigned int fake = *(unsigned int *)&rtn;    \
  438.     double_identity_function(rtn);            \
  439.     return(fake);                    \
  440.     })
  441.  
  442.   /* don't inline this */
  443.   static double double_identity_function(x) { return(x); }
  444.  
  445.  
  446. Richard further proposes:
  447. >  struct datum { int typeclass; int size; void *address; };
  448.  
  449. I don't think this machine-specific encoding is currently accessible
  450. at run-time, because __builtin_classify_type() is of necessity a
  451. compiler directive rather than an honest function call (due to the way
  452. it is "called").
  453.  
  454. I think what is needed here is a simple, portable type
  455. encoding---which conveniently enough already exists.  The Objective-C
  456. runtime uses a simple string encoding which covers all possible C
  457. types, including compound types.  So I'd suggest
  458.  
  459.   struct datum { const char *typedesc; void *address; };
  460.  
  461. You'd need to write a library function to convert this to the
  462. machine-specific form, but the code for it would be simple, and
  463. more-or-less xeroxed from BUILT_IN_CLASSIFY_TYPE.  Actually, for
  464. better efficiency, we could even leave space in the datum structure
  465. for caching the machine-specific info:
  466.  
  467.   struct datum
  468.   {
  469.       /* User-level information */
  470.       const char *typedesc;
  471.     void *address;
  472.  
  473.     /* System-cached information */
  474.     int typeclass;
  475.     int size;
  476.   };
  477.  
  478. --------------------------------------------------------------------
  479. Paul Burchard    <burchard@geom.umn.edu>
  480. ``I'm still learning how to count backwards from infinity...''
  481. --------------------------------------------------------------------
  482.  
  483. Date: Sat, 23 Jan 93 19:55:49 -0500
  484. From: rms@gnu.ai.mit.edu (Richard Stallman)
  485. To: burchard@geom.umn.edu
  486. Cc: gnu-objc@prep.ai.mit.edu
  487. In-Reply-To: <9301232120.AA15572@mobius.geom.umn.edu> (burchard@geom.umn.edu)
  488. Subject: The forward/performv Puzzle
  489.  
  490.     The above is what is needed for performv.  For forwarding (and to get  
  491.     the full benefit of the above facility) the opposite capability is  
  492.     also required---namely, the ability for a single function to receive  
  493.     calls issued with varying prototypes.
  494.  
  495. Doesn't varargs accomplish that?
  496.  
  497. But we do need in addition a way to find out what sorts of arguments a
  498. given method expects.
  499.  
  500.     I don't think this machine-specific encoding is currently accessible  
  501.     at run-time, because __builtin_classify_type() is of necessity a  
  502.     compiler directive rather than an honest function call (due to the  
  503.     way it is "called").
  504.  
  505. It is true that ___builtin_classify_type is only computed at compile time,
  506. but that isnot a problem.  There is no occasion in the scheme I proposed
  507. to wish it were otherwise.
  508.  
  509.  
  510. Date: Sat, 23 Jan 93 20:05:37 -0600
  511. From: burchard@geom.umn.edu
  512. To: rms@gnu.ai.mit.edu (Richard Stallman)
  513. Subject: Re: The forward/performv Puzzle
  514. Cc: gnu-objc@prep.ai.mit.edu
  515.  
  516. [More about RMS's excellent "apply" idea...]
  517. >
  518. > > [Paul wants] the ability for a single function to receive 
  519. > > calls issued with varying prototypes.
  520. >
  521. > Doesn't varargs accomplish that?
  522.  
  523. Unfortunately not.  The "apply" extension is supposed to be a run-time
  524. version of function-pointer casting, and thus compatible with function
  525. prototypes.  This unfortunately makes it *incompatible* with varargs,
  526. because "..." arguments effectively use a different calling convention
  527. than normal prototyped arguments (due to type promotion).
  528.  
  529. And of course varargs only attempts to handle argument types, not return types.
  530.  
  531. > But we do need in addition a way to find out what sorts of
  532. > arguments a given method expects.
  533.  
  534. Correct---in this respect the "apply" extension is no different than
  535. varargs; we must use "required" args (or something similar) to get
  536. that info.
  537.  
  538. In an Obj-C forwarding implementation, self and _cmd would be the
  539. required args.  The Obj-C runtime would be able to determine from that
  540. data what the remaining expected arg types were.
  541.  
  542. > It is true that ___builtin_classify_type is only
  543. > computed at compile time, but that isnot a problem.  There
  544. > is no occasion in the scheme I proposed to wish it were
  545. > otherwise.
  546.  
  547. This may be true if "apply" is simply a way of avoiding large case
  548. statements (i.e., if you always "apply" functions consistently with
  549. their prototypes, which are in principle known at compile time).
  550.  
  551. However, Obj-C forwarding requires that we be able to "apply" a fixed
  552. function as if it had different prototypes.  Moreover, in a
  553. distributed object setting, those prototypes may not---even in
  554. principle!---be knowable at compile time.  Therefore, the type system
  555. must be fully accessible at run time.
  556.  
  557. Actually, this isn't worth haggling over, because the run-time
  558. equivalent of ___builtin_classify_type is so trivial to write.
  559.  
  560. --------------------------------------------------------------------
  561. Paul Burchard    <burchard@geom.umn.edu>
  562. ``I'm still learning how to count backwards from infinity...''
  563. --------------------------------------------------------------------
  564.  
  565. From: Andrew Athan <wiltel!aathan@uunet.uu.net>
  566. Date: Tue, 26 Jan 93 09:59:22 -0600
  567. To: gnu-objc-runtime@prep.ai.mit.edu
  568. Subject: forward/performv: summary
  569.  
  570.  
  571. I'm not sure how many of you (probably all of you?) are on the
  572. gnu-objc list, so I am forwarding parts of a discussion on
  573. implementing forward:/performv: behavior in gnu-objc (this is
  574. currently missing).
  575.  
  576. No-one has yet volunteered to write the code.
  577.  
  578. aca
  579. -----------------------------------------------------
  580. > uunet!geom.umn.edu!burchard -- started this all off
  581.  
  582. > There is one major feature missing from GNU's Objective-C run-time
  583. > at the moment, which prevents this project from progressing to the
  584. > more desirable very, very preliminary :-) stage.  That feature is the
  585. > functionality of NeXT's forward and performv, which are required in
  586. > order that arbitrary messages can be captured by proxy objects and
  587. > then later executed by the remote objects they stand for.
  588.  
  589.  
  590. >Michael Gersten
  591. > To avoid lots of hypothetical discussions, I suggest everyone
  592. > thinking about this take a look at section 14.7 of the GNU CC manual,
  593. > on C calling conventions (about a dozen pages).
  594.  
  595. >Dennis Glatting on some of the issues
  596. > * Implementation of forwardv:: would require stack frame copying.
  597. > (or at least modification of the existing stack frame.)
  598. > * The microprocessor itself poses problems such as word width,
  599. > alignment, and -- possibly on some RISC machines -- parameter passing
  600. > using register windows.
  601. > * Each function used to implement forwardv:: may need to know the
  602. > amount of data pushed onto the stack for local variables.  (So to
  603. > index backward.)
  604. > * The dispatch function must know about passed arguments.  While this
  605. > is encoded and available, what do you do for variable arguments and
  606. > structures?  Oh yea, how about void*?
  607. > * The stack must be indexed to extract return addresses -- that is, if
  608. > this can be done with your microprocessor of the day.  There are also
  609. > microprocessor/compiler specific data pushed onto the stack that the
  610. > functions may need to know about such as the variable frame on 680x0
  611. > microprocessors (note the link instruction on each function entry).
  612.  
  613. > uunet!geom.umn.edu!burchard -- a summary of what needs to be done
  614. > 1. id objc_msgSend(id self, SEL op);
  615.     return objc_forwardingHandler if method missing
  616.  
  617. 2. id objc_forwardingHandler(id self, SEL op);
  618.     ask runtime for expected arg types, based on self and op
  619.     use __builtin_get_args() to get those expected args
  620.     send -forward::return: to object if it implements it, passing
  621.         back the return value with __builtin_put_return()
  622.     else call usual runtime error handler
  623.     
  624. 3. -forward:(SEL)op :(typed_data_t *)args return:(typed_data_t)rtn;
  625.     [optional instance method]
  626.  
  627. 4. -perform:(SEL)op :(typed_data_t *)args return:(typed_data_t)rtn;
  628.     [builtin Object method]
  629.     use __builtin_apply() to call objc_msgSend() with the
  630.         correct cast for the method being performed
  631.     [this scheme will allow the call to be forwarded again]
  632.  
  633. 5. void __builtin_get_args(typed_data_t *args);
  634.     [a convenience built on GCC's varargs support]
  635.     insert __builtin_saveregs()
  636.     loop through the given type info:
  637.         get low-level info with __builtin_classify_typedesc()
  638.         use varargs code, ___builtin_args_info(), and
  639.             __builtin_next_arg()) to do the real work
  640.     [we can't use va macros because this is a runtime operation]
  641.  
  642. 6. void __builtin_classify_typedesc(typed_data_t *data);
  643.     [run-time version of GCC's __builtin_classify_type(),
  644.         __alignof__(), and sizeof() combined]
  645.     fill in machine-dependent fields of structure, based on
  646.         given type descriptor string
  647.  
  648. 7. void __builtin_put_return(typed_data_t value);
  649.     machine-dependent; based on GNU CC return convention macros
  650.     [REQUIRES SOME WORK]
  651.     
  652. 8. void __builtin_apply(typed_data_t rtn; void (*f)(), typed_data_t *args);
  653.     machine-dependent; based on calling conventions...
  654.     [REQUIRES REAL WORK]
  655.  
  656. [In the above, we are using
  657.  
  658.     typedef struct _typed_data_t {
  659.         const char *typedesc;        /* as in Obj-C */
  660.         void *value;
  661.         /* ... fields for machine-dependent data... */
  662.     } typed_data_t;
  663.  
  664. > Rms' call to arms
  665. > rms> Please tell me if you volunteer to write this.
  666.  
  667. aca
  668.  
  669. From: "Geoffrey S. Knauth" <gsk@marble.com>
  670. Date: Sun, 31 Jan 93 13:35:19 -0500
  671. To: gsk@marble.com
  672. Subject: [rms@gnu.ai.mit.edu: The forward/performv Puzzle]
  673.  
  674. Return-Path: <rms@gnu.ai.mit.edu>
  675. Date: Sun, 24 Jan 93 14:24:41 -0500
  676. From: rms@gnu.ai.mit.edu (Richard Stallman)
  677. To: burchard@geom.umn.edu
  678. Cc: gnu-objc@prep.ai.mit.edu
  679. In-Reply-To: <9301240205.AA15818@mobius.geom.umn.edu> (burchard@geom.umn.edu)
  680. Subject: The forward/performv Puzzle
  681.  
  682.     > It is true that ___builtin_classify_type is only
  683.     > computed at compile time, but that isnot a problem.  There
  684.     > is no occasion in the scheme I proposed to wish it were
  685.     > otherwise. 
  686.  
  687.  
  688.     This may be true if "apply" is simply a way of avoiding large case  
  689.     statements (i.e., if you always "apply" functions consistently with  
  690.     their prototypes, which are in principle known at compile time).  
  691.  
  692.  
  693.     However, Obj-C forwarding requires that we be able to "apply" a fixed  
  694.     function as if it had different prototypes.
  695.  
  696. That is not how I envision apply to be used.  apply is to be used to
  697. call an individual method chosen at run time.  Each method has a fixed
  698. set of argument types.  In a correct program, it will always be applied
  699. with arguments of those types.
  700.  
  701. The forwarder will be called with arguments of different types,
  702. but it will not be called with apply.  It *uses* apply.
  703.  
  704.  
  705.  
  706. From: "Geoffrey S. Knauth" <gsk@marble.com>
  707. Date: Sun, 31 Jan 93 13:35:27 -0500
  708. To: gsk@marble.com
  709. Subject: [burchard@geom.umn.edu: Re: The forward/performv Puzzle]
  710.  
  711. Return-Path: <burchard@geom.umn.edu>
  712. Date: Sun, 24 Jan 93 14:42:07 -0600
  713. From: burchard@geom.umn.edu
  714. To: gnu-objc@prep.ai.mit.edu
  715. Subject: Re: The forward/performv Puzzle
  716.  
  717. > > However, Obj-C forwarding requires that we be able to "apply" a 
  718.  
  719. > > fixed function as if it had different prototypes.
  720.  
  721. > The forwarder will be called with arguments of different
  722. > types, but it will not be called with apply.
  723.  
  724. Exactly: the forwarding handler in the Obj-C run-time has no choice  
  725. about the way it is called, because once a pointer to it is returned  
  726. from objc_msgSend(), BAM!, it gets called as if it had the prototype  
  727. of the desired (missing) method.  So certainly, we have no chance to  
  728. call it with "apply".
  729.  
  730. OK, so now we are inside that forwarding handler, having been sent  
  731. the arguments the method would have expected, and we want to either  
  732. "apply" some replacement method to those args, or ship off the arg  
  733. frame to something like a forward:: method, or make use of whatever  
  734. your favorite forwarding protocol is (more on this below).
  735.  
  736. But...but...how do we get a hold of those args that we were sent, in  
  737. order to "apply" a new method to them, or forward:: them somewhere  
  738. else?  And once we determine a return value, how do we get that out  
  739. of the the forwarding handler and back into the code the missing  
  740. method was called from?  This is why forwarding requires "get_args"  
  741. and "put_return", not just "apply".
  742.  
  743. > It *uses* apply. 
  744.  
  745.  
  746. Actually, that would be tragic.  If it's going to be of any use for  
  747. distributed objects, the forwarding handler cannot presume upon  
  748. itself the sole power to call a replacement method.  After all, the  
  749. replacement method may need to be called in a completely different  
  750. execution context!
  751.  
  752. For this reason, the "forward" and "perform" parts of the  
  753. method-replacement process must be cleanly separated; only "perform"  
  754. is allowed to use "apply".  We get a 3-step process:
  755.  
  756. 1.  objc_msgSend() offers up a forwarding handler to be called in  
  757. place of the missing method.  This handler bundles up the args into a  
  758. standard format, and passes along the expected return value when it's  
  759. all over.  [This uses only "get_args" and "put_return".]
  760.  
  761. 2.  Using some standard Obj-C "forward" message, the forwarding  
  762. handler passes all this information, in standard format, to the  
  763. object whose method was missing.  [This uses nothing special.]
  764.  
  765. 3.  The object may do whatever it likes with this information.  One  
  766. possibility is to compute a new object, selector, and arg frame from  
  767. the given information, and pass that to some standard Obj-C "perform"  
  768. message.  Another possibility is to send instructions to a remote  
  769. process to do the same.  [This uses only "apply".]
  770.  
  771. In other words, NeXT (or would that be Steve?) basically discovered  
  772. the right strategy for forwarding; the API just needs a bit of  
  773. touching up.
  774.  
  775. --------------------------------------------------------------------
  776. Paul Burchard    <burchard@geom.umn.edu>
  777. ``I'm still learning how to count backwards from infinity...''
  778. --------------------------------------------------------------------
  779.  
  780.  
  781.  
  782.  
  783. From: "Geoffrey S. Knauth" <gsk@marble.com>
  784. Date: Sun, 31 Jan 93 13:35:37 -0500
  785. To: gsk@marble.com
  786. Subject: [rms@gnu.ai.mit.edu: The forward/performv Puzzle]
  787.  
  788. Return-Path: <rms@gnu.ai.mit.edu>
  789. Date: Sun, 24 Jan 93 17:05:49 -0500
  790. From: rms@gnu.ai.mit.edu (Richard Stallman)
  791. To: gnu-objc@prep.ai.mit.edu
  792. In-Reply-To: <9301242041.AA16505@mobius.geom.umn.edu> (burchard@geom.umn.edu)
  793. Subject: The forward/performv Puzzle
  794.  
  795.     But...but...how do we get a hold of those args that we were sent, in  
  796.     order to "apply" a new method to them, or forward:: them somewhere  
  797.     else?
  798.  
  799. It should work to do this with varargs, even when args have promotable
  800. types such as float.  A properly declared "real" varargs function will
  801. never receive a nameless arg of type float, as it would have been
  802. promoted to double.  But it will work in the forwarder to use va_arg
  803. for an arg of type float if that is what was passed.
  804.  
  805. As for finding out how many args were passed, and of what type,
  806. you need to get that from the tables defining the methods of the class.
  807.  
  808. Storing the return value does need some new construct.
  809. A new built-in function should be able to do the job.
  810.  
  811.     Actually, that would be tragic.  If it's going to be of any use for  
  812.     distributed objects, the forwarding handler cannot presume upon  
  813.     itself the sole power to call a replacement method.  After all, the  
  814.     replacement method may need to be called in a completely different  
  815.     execution context!
  816.  
  817. I have not been using your distinction between "forward" and
  818. "perform".  When I talk of "the forwarder" I have been alking about
  819. the whole process of forwarding a message to another object.
  820.  
  821.  
  822.  
  823. From: "Geoffrey S. Knauth" <gsk@marble.com>
  824. Date: Sun, 31 Jan 93 13:35:45 -0500
  825. To: gsk@marble.com
  826. Subject: [burchard@geom.umn.edu: Light at the end of the forwarding tunnel?]
  827.  
  828. Return-Path: <burchard@geom.umn.edu>
  829. Date: Sun, 24 Jan 93 17:00:20 -0600
  830. From: burchard@geom.umn.edu
  831. To: rms@gnu.ai.mit.edu (Richard Stallman)
  832. Subject: Light at the end of the forwarding tunnel?
  833. Cc: gnu-objc@prep.ai.mit.edu
  834.  
  835. > > But...but...how do we get a hold of those args that we were
  836. > > sent, in   order to "apply" a new method to them, or
  837. > > forward:: them somewhere   else? 
  838.  
  839.  
  840. > With varargs.  This can work, even when args have
  841. > promotable types such as float.  A "real" varargs
  842. > function will never receive an arg of type float, but it
  843. > will work in the forwarder to ask for an arg of type float if
  844. > that is what it was given.  
  845.  
  846.  
  847. Aha, I didn't realize GCC's varargs support was already general  
  848. enough to handle non-promoted arg types.  That's wonderful!
  849.  
  850. I stand, happily, corrected.  This saves over 1/3 of the work!
  851.  
  852. > Storing the return value does need some new construct. A
  853. > new built-in function should be able to do the job. 
  854.  
  855.  
  856. Right, and this won't be nearly as complicated as grabbing args.
  857.  
  858. > I have not been using your distinction between "forward"
  859. > and "perform".  When I talk of "the forwarder" I have been
  860. > alking about the whole process of forwarding a message to
  861. > another object. 
  862.  
  863.  
  864. OK, I'm glad we're on the same wavelength. So, here is an 8-step plan  
  865. of what needs to be done.  The "apply" function appears once again as  
  866. the biggest job:
  867.  
  868. 1. id objc_msgSend(id self, SEL op);
  869.     return objc_forwardingHandler if method missing
  870.  
  871. 2. id objc_forwardingHandler(id self, SEL op);
  872.     ask runtime for expected arg types, based on self and op
  873.     use __builtin_get_args() to get those expected args
  874.     send -forward::return: to object if it implements it, passing
  875.         back the return value with __builtin_put_return()
  876.     else call usual runtime error handler
  877.     
  878. 3. -forward:(SEL)op :(typed_data_t *)args return:(typed_data_t)rtn;
  879.     [optional instance method]
  880.  
  881. 4. -perform:(SEL)op :(typed_data_t *)args return:(typed_data_t)rtn;
  882.     [builtin Object method]
  883.     use __builtin_apply() to call objc_msgSend() with the
  884.         correct cast for the method being performed
  885.     [this scheme will allow the call to be forwarded again]
  886.  
  887. 5. void __builtin_get_args(typed_data_t *args);
  888.     [a convenience built on GCC's varargs support]
  889.     insert __builtin_saveregs()
  890.     loop through the given type info:
  891.         get low-level info with __builtin_classify_typedesc()
  892.         use varargs code, ___builtin_args_info(), and
  893.             __builtin_next_arg()) to do the real work
  894.     [we can't use va macros because this is a runtime operation]
  895.  
  896. 6. void __builtin_classify_typedesc(typed_data_t *data);
  897.     [run-time version of GCC's __builtin_classify_type(), 
  898.  
  899.         __alignof__(), and sizeof() combined]
  900.     fill in machine-dependent fields of structure, based on
  901.         given type descriptor string
  902.  
  903. 7. void __builtin_put_return(typed_data_t value);
  904.     machine-dependent; based on GNU CC return convention macros
  905.     [REQUIRES SOME WORK]
  906.     
  907. 8. void __builtin_apply(typed_data_t rtn; void (*f)(), typed_data_t  
  908. *args);
  909.     machine-dependent; based on calling conventions...
  910.     [REQUIRES REAL WORK]
  911.  
  912. [In the above, we are using
  913.  
  914.     typedef struct _typed_data_t {
  915.         const char *typedesc;        /* as in Obj-C */
  916.         void *value;
  917.         /* ... fields for machine-dependent data... */
  918.     } typed_data_t;
  919.  
  920. So is it time to start dividing this task up?  Are people excited?   
  921. Or should we plan the implementation of the "apply" function in more  
  922. detail first?
  923.  
  924. --------------------------------------------------------------------
  925. Paul Burchard    <burchard@geom.umn.edu>
  926. ``I'm still learning how to count backwards from infinity...''
  927. --------------------------------------------------------------------
  928.  
  929.  
  930.  
  931.  
  932. From: "Geoffrey S. Knauth" <gsk@marble.com>
  933. Date: Sun, 31 Jan 93 13:35:55 -0500
  934. To: gsk@marble.com
  935. Subject: [casey!gaboon!seltd!lerman@uunet.uu.net: Re: The forward/performv Puzzle]
  936.  
  937. Return-Path: <casey!gaboon!seltd!lerman@uunet.uu.net>
  938. From: Kenneth Lerman <casey!gaboon!seltd!lerman@uunet.uu.net>
  939. X-Mailer: SCO System V Mail (version 3.2)
  940. To: burchard@geom.umn.edu, rms@gnu.ai.mit.edu
  941. Subject: Re: The forward/performv Puzzle
  942. Cc: gnu-objc@prep.ai.mit.edu
  943. Date: Sun, 24 Jan 93 15:06:11 EST
  944.  
  945.  
  946. It was asked:
  947. |    The above is what is needed for performv.  For forwarding (and to get
  948. |    the full benefit of the above facility) the opposite capability is
  949. |    also required---namely, the ability for a single function to receive
  950. |    calls issued with varying prototypes.
  951.  
  952. |Doesn't varargs accomplish that?
  953.  
  954. No, it does not.  Varargs, in general, only works if the function was
  955. declared to have a variable number of arguments.  Of course, some
  956. compilers on some platforms may have a varargs which will work anyway.
  957.  
  958. Ken
  959.  
  960.  
  961.  
  962. From: "Geoffrey S. Knauth" <gsk@marble.com>
  963. Date: Sun, 31 Jan 93 13:39:29 -0500
  964. To: gsk@marble.com
  965. Subject: [Steve_Naroff@next.com: Re: The forward/performv Puzzle]
  966.  
  967. Return-Path: <Steve_Naroff@next.com>
  968. From: Steve Naroff <Steve_Naroff@next.com>
  969. Date: Mon, 25 Jan 93 10:43:32 -0800
  970. To: rms@gnu.ai.mit.edu (Richard Stallman)
  971. Subject: Re: The forward/performv Puzzle
  972. Cc: Steve_Naroff@next.com, dennis_glatting@trirex.com,
  973.         gnu-objc@prep.ai.mit.edu, wood@next.com, mwagner@next.com
  974.  
  975.  
  976. rms> Please tell me if you volunteer to write this.
  977.  
  978. I am real busy, but Tom Wood (who now works with me) might be  
  979. interested in writing this. I will discuss it with him.
  980.  
  981. thanks, snaroff.
  982.  
  983. Return-Path: <burchard@localhost.gw.umn.edu>
  984. Date: Sat, 20 Feb 93 14:04:33 -0600
  985. From: Paul Burchard <burchard@localhost.gw.umn.edu>
  986. To: Kresten Krab Thorup <krab@iesd.auc.dk>
  987. Subject: Re: Optimizing the GNU objc runtime
  988. Cc: gnu-objc@gnu.ai.mit.edu
  989. Reply-To: burchard@geom.umn.edu
  990.  
  991. Kresten Krab Thorup <krab@iesd.auc.dk> writes:
  992. > We will here use the trick of installing a special
  993. > method __objc_missingMethod at all indices for which
  994. > there do not exist a corresponding message.  That
  995. > function handles the case where a message is not
  996. > recognized, and if possible, forward the message to
  997. > `doesNotRecognize:' in the receiver.
  998.  
  999. This is a good trick---and it thankfully leaves open a way to  
  1000. implement full-fledged forwarding as previously discussed on this  
  1001. mailing list.  Not only that, but your proposed system should even  
  1002. make forwarding noticeably faster, by cutting the message dispatch  
  1003. overhead, which is normally paid several extra times during the  
  1004. forwarding process.
  1005.  
  1006. Your proposal seems like a good idea; I'd love to have efficient  
  1007. messaging for some numerical algorithms I'm working with.  My only  
  1008. question would be how much time a "typical" program would spend at  
  1009. startup, filling all the dispatch caches. Would the wait be  
  1010. noticeable on a human timescale?  (If you have ~100 classes with ~100  
  1011. methods each, and you want to keep extra startup overhead to no more  
  1012. than 1/20 second, that only allows you 5 ms per lookup.)
  1013.  
  1014. --------------------------------------------------------------------
  1015. Paul Burchard    <burchard@geom.umn.edu>
  1016. ``I'm still learning how to count backwards from infinity...''
  1017. --------------------------------------------------------------------
  1018.  
  1019. Return-Path: <krab@iesd.auc.dk>
  1020. Date: Sun, 21 Feb 1993 23:22:37 +0100
  1021. From: Kresten Krab Thorup <krab@iesd.auc.dk>
  1022. To: rms@gnu.ai.mit.edu (Richard Stallman)
  1023. In-Reply-To: <9302212157.AA01459@mole.gnu.ai.mit.edu>
  1024. Subject: Re: Gnu objc runtime [comments and bug reports]
  1025. Cc: krab@iesd.auc.dk, gsk@marble.com
  1026.  
  1027. Richard Stallman writes:
  1028. >Could you please send me individual separate patches for those three
  1029. >problems?
  1030.  
  1031. Do you really want this?  Most of these bugfixes are outdated the
  1032. moment I implement the new messenger and initialization mechanism
  1033. described in my papers `Optimizing ...' and `How to do lookup...'.
  1034. In my oppinion it would be waste of time patching up the current
  1035. runtime, at least `core.c'. 
  1036.  
  1037. Realize the facts:  This is a completely new runtime, since an objc
  1038. runtime is practically nothing but initialization an message lookup.  
  1039.  
  1040. I have been working hard for the last days, trying to convince you
  1041. that I actually do know what I am talking about.  This is what you
  1042. questioned in the first place.
  1043.  
  1044. I am willing to supply the patches you requested, but I would rather,
  1045. if I was `allowed' to recode the initialization and lookup sections
  1046. completely.  
  1047.  
  1048. All I need in order to do this is that special `__builtin_forward'
  1049. which I am not able to program myself, since I am not into assember,
  1050. neither the internals of gcc.  However, if you would do this for me,
  1051. you should do it for sparc architecture first, since I am sitting on a
  1052. Sun.
  1053.  
  1054. Regards, Thanks, Please, etc.
  1055. Kresten
  1056.  
  1057. NOTE // The letter is Cc'ed to gsk since it contains essential
  1058.     questions for the gnu-objc project.            //
  1059.  
  1060.